package com.cf.game.gate.core;

import com.cf.constant.EnumReturnCode;
import com.cf.exception.BizException;
import com.cf.exception.BizStackException;
import com.cf.game.gate.config.GateProperty;
import com.cf.game.msg.EnumCommonMessageType;
import com.cf.game.msg.PathConstant;
import com.cf.game.msg.Request;
import com.cf.game.msg.Response;
import com.cf.game.node.Node;
import com.cf.game.node.NodeService;
import com.cf.game.node.Pressure;
import com.cf.game.vertx.DeployWorkerVerticle;
import com.cf.util.ObjectJsonUtil;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Handler;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.http.ServerWebSocket;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * boot-awm-WSGate
 * <p>
 * web-socket 接口
 *
 * @author <a href="2428922347@qq.com">Zhu mingming</a>
 * @info
 * @since 2018/6/27 上午 10:25
 */
@Slf4j
@DeployWorkerVerticle
public class WSGate extends AbstractVerticle {


    private String listenQueue = "";

    @Autowired
    private WSService wsService;

    @Autowired
    private NodeService nodeService;

    @Autowired
    private GateProperty gateProperty;

    @Override
    public void start() throws Exception {
        createMetaTree();
        createWebSocketServer();
        configEventBus();
    }

    private void configEventBus() {
        EventBus ebs = vertx.eventBus();
        log.info("开始监听事件总线【{}】", listenQueue);
        ebs.consumer(listenQueue, message -> {
            String msg = String.valueOf(message.body());
            Response response = ObjectJsonUtil.toObject(msg, Response.class);
            if (response == null)
                return;
            wsService.deliveryMessage(response.getUserId(), msg);
        });
    }

    private void createWebSocketServer() {
        EventBus eventBus = vertx.eventBus();
        vertx.createHttpServer().websocketHandler(ws -> {

            String loginInfo = ws.query();
            log.info("【{}】试图建立连接。。。。。", loginInfo);
            UserWrapper userWrapper = wsService.checkUser(loginInfo, ws, listenQueue);
            if (userWrapper == null) {
                ws.writeFinalTextFrame("未授权的连接！");
                ws.reject();
            }

            log.info("【{}】连接通过验证,当前节点是【{}】", loginInfo, listenQueue);
            ws.closeHandler(new Handler<Void>() {
                @Override
                public void handle(Void event) {
                    wsService.logout(ws);
                }
            });


            ws.exceptionHandler(new Handler<Throwable>() {
                @Override
                public void handle(Throwable event) {
                    if (event instanceof BizException) {
                        BizException bizException = (BizException) event;
                        ws.writeFinalTextFrame(ObjectJsonUtil.toString(Response.instance(0, bizException.getCode(), bizException.getMessage())));
                        return;
                    }
                    if (event instanceof BizStackException) {
                        BizStackException bizException = (BizStackException) event;
                        ws.writeFinalTextFrame(ObjectJsonUtil.toString(Response.instance(0, bizException.getCode(), bizException.getMessage())));
                        return;
                    }
                    ws.writeFinalTextFrame(ObjectJsonUtil.toString(Response.instance(0, EnumReturnCode.ERROR.getCode(), "数据处理异常！")));
                }
            });

            ws.textMessageHandler(new Handler<String>() {
                @Override
                public void handle(String msg) {
                    distributeMessage(msg, eventBus, ws);
                }
            });

        }).listen(8080, gateProperty.getBind());
    }

    private void distributeMessage(String msg, EventBus eventBus, ServerWebSocket ws) {
        Request request = ObjectJsonUtil.toObject(msg, Request.class);
        if (request != null) {

            /**
             * 聊天消息
             */
            if (EnumCommonMessageType.CHAT.getMessageType().equals(request.getType())) {
                String path = nodeService.getSuitableNode(PathConstant.TAIK_PARENT_PATH);
                if (!StringUtils.isEmpty(path)) {
                    eventBus.publish(path, request.getMsg());
                }
            }


            /**
             * 获取自己的消息
             */
            if (EnumCommonMessageType.SELF.getMessageType().equals(request.getType())) {
                wsService.selfInfo(ws);
            }

        }
    }


    private void createMetaTree() {
        listenQueue = nodeService.registerNode(Node.instance(PathConstant.WS_GATE_NAME, PathConstant.WS_GATE_PARENT_PATH), Pressure.instance(10));
    }

}
